package com.zj.util.concurrent;

import com.zj.common.exception.CommonException;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author zhangbo
 * @program: PDF-helper
 * @ClassName KernelRejectedExecutionHandler
 * @description: $
 * @date 2023-05-27 21:47:25
 */
@Slf4j
public class KernelRejectedExecutionHandler implements RejectedExecutionHandler {


    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

    }

    //TODO 后续可增加通过mq等工具进行异步处理


    /**
     * 返回给调用者线程
     * 在该策略下，在调用者中执行被拒绝任务的run方法。如果线程池showdown，则抛弃执行
     */
    public static class CallerRunsPolicy extends KernelRejectedExecutionHandler {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

            log.info("[CallerRunsPolicy] 当前 {} 任务使用的线程池已满，正在执行 CallerRunsPolicy 饱和策略....", r.toString());
            if (!executor.isShutdown()) {
                r.run();
            }
        }
    }


    /**
     * 终止策略
     * 丢弃拒绝的任务，并抛出异常进行警告
     */
    public static class AbortPolicy extends KernelRejectedExecutionHandler {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

            log.info("[AbortPolicy] 当前 {} 任务使用的线程池已满，正在执行 AbortPolicy 饱和策略....", r.toString());

            throw new CommonException("当前线程池已满，请及时处理当前任务：" + r);
        }
    }


    /**
     * 丢弃最老线程
     * 丢弃最早放入等待队列中的线程，并尝试将拒绝线程重新放到线程池中执行
     */
    public static class DiscardOldestPolicy extends KernelRejectedExecutionHandler {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

            log.info("[DiscardOldestPolicy] 当前 {} 任务使用的线程池已满，正在执行 DiscardOldestPolicy 饱和策略....", r.toString());

            if (!executor.isShutdown()) {
                Runnable discardThread = executor.getQueue().poll();
                log.info("[DiscardOldestPolicy] 已经将该线程丢掉 {}", discardThread);
                executor.execute(r);
            }
        }
    }






}
